package com.gitee.wsl.doc.prosemirror.transform.ext

import com.gitee.wsl.doc.prosemirror.model.Whitespace
import com.gitee.wsl.doc.prosemirror.model.content.ContentMatch
import com.gitee.wsl.doc.prosemirror.model.fragment.Fragment
import com.gitee.wsl.doc.prosemirror.model.fragment.Slice
import com.gitee.wsl.doc.prosemirror.model.node.NodeType
import com.gitee.wsl.doc.prosemirror.transform.TransformAble
import com.gitee.wsl.doc.prosemirror.transform.step.RemoveMarkStep
import com.gitee.wsl.doc.prosemirror.transform.step.ReplaceStep
import com.gitee.wsl.doc.prosemirror.transform.step.Step


fun<T: TransformAble> T.clearIncompatible(
    pos: Int,
    parentType: NodeType,
    match: ContentMatch? = parentType.contentMatch,
    clearNewlines: Boolean = true
)= apply {
    val tr = this
    var match = match ?: parentType.contentMatch
    val node = tr.doc.nodeAt(pos)!!
    val replSteps = mutableListOf<Step>()
    var cur = pos + 1
    for (i in 0 until node.childCount) {
        val child = node.child(i)
        val end = cur + child.nodeSize
        val allowed = match.matchType(child.type)
        if (allowed == null) {
            replSteps.add(ReplaceStep(cur, end, Slice.empty))
        } else {
            match = allowed
            for (j in 0 until child.marks.size)
                if (!parentType.allowsMarkType(child.marks[j].type)) {
                    tr.step(RemoveMarkStep(cur, end, child.marks[j]))
                }
            if (clearNewlines && child.isText && parentType.whitespace != Whitespace.PRE) {
                val newline = Regex("\r?\n|\r")
                var slice: Slice? = null
                val text = child.text ?: ""
                newline.findAll(text).forEach {
                    if (slice == null) {
                        slice = Slice(
                            Fragment.from(parentType.schema.text(" ", parentType.allowedMarks(child.marks))),
                            0,
                            0
                        )
                    }
                    replSteps.add(ReplaceStep(cur + it.range.first, cur + it.range.last + 1, slice!!))
                }
            }
        }
        cur = end
    }
    if (!match.validEnd) {
        val fill = match.fillBefore(Fragment.empty, true)
        tr.replace(cur, cur, Slice(fill!!, 0, 0))
    }
    for (i in replSteps.size - 1 downTo 0) {
        tr.step(replSteps[i])
    }
}